/*
 *  Copyright 2008-2010 www.jrails.org
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package org.rails.core.db.table;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import javax.sql.DataSource;

import org.apache.log4j.Logger;
import org.rails.core.GLOBAL;
import org.rails.core.model.ActiveRecordBase;
import org.rails.core.resource.ConfigBuilder;
import org.rails.core.resource.ResourceFactory;
import org.rails.core.util.Utils;

public final class Table {

	private final Logger logger = Logger.getLogger(this.getClass());

	private final ConfigBuilder config = ResourceFactory.getConfigBuilder();
	
	private final String PK_TYPE_AUTO = "Auto";
	private final String PK_TYPE_UUID = "UUID";

	private String primaryKey;
	private String name;
	private String columnFormat;
	private String format;
	private boolean call;
	private Class<? extends AttributeMap> pkType;
	private DataSource dataSource;

	public Table(DataSource dataSource,Class<? extends ActiveRecordBase> model) {
		super();
		this.dataSource = dataSource;
		initPK(model.getSimpleName());
		initName(model.getSimpleName());
		initCall(model.getSimpleName());
		initPKType(model.getSimpleName());
		initForamt(model.getSimpleName());
	}
	
	public Table(DataSource dataSource,String name) {
		super();
		this.dataSource = dataSource;
		this.name = name;
		String modelName = NameUtils.toPascalName(name);
		initPK(modelName);
		initCall(modelName);
		initPKType(modelName);
		initForamt(modelName);
	}
	
	private void initPK(String simpleName){
		final String key = Utils.format("{0}.table.primaryKey", simpleName);
		primaryKey = config.getConfigValue(key, GLOBAL.SYSTEM_DEFAULT_PRIMARY_KEY_NAME);
	}
	
	private void initName(String simpleName){
		final String key = Utils.format("{0}.table.name", simpleName);
		if (config.containsKey(key)) {
			name = config.get(key);
		} else {
			name = NameUtils.toUnderName(simpleName);
		}
		name = config.get(Utils.format("{0}.table.prefix",simpleName),"") + name;
	}
	
	private void initForamt(String simpleName){
		final String frmKey = Utils.format("{0}.table.format",simpleName);
		final String colKey = Utils.format("{0}.column.format",simpleName);
		format = config.getConfigValue(frmKey,"[table]");
		columnFormat = config.getConfigValue(colKey,"[column]");
	}
	
	
	private void initCall(String simpleName){
		final String key = Utils.format("{0}.primaryKey.call",simpleName);
		call = Boolean.parseBoolean(config.getConfigValue(key,"false"));
	}
	
	@SuppressWarnings("unchecked")
	private void initPKType(String simpleName){
		String key = Utils.format("{0}.primaryKey.type",simpleName);
		String type = config.getConfigValue(key,PK_TYPE_AUTO);
		if(type.equals(PK_TYPE_AUTO)){
			pkType = Auto.class;
		}else if(type.equals(PK_TYPE_UUID)){
			pkType = UUID.class;
		}else{
			try {
				pkType = (Class<? extends AttributeMap>) Class.forName(type);
			} catch (ClassNotFoundException e) {
				logger.error(e.getMessage(),e);
			}
		}
	}

	public Columns getColumns() {
		return new Columns(dataSource, getName());
	}
	
	
	/**
	 * 获取主键名称，默认为"ID"。
	 * @return 返回主键的名称。
	 */
	public String getPrimaryKey() {
		return primaryKey;
	}

	/**
	 * 获取表名称。
	 * @return 表名称。
	 */
	public String getName() {
		return name;
	}
	
	/**
	 * 获取表名称,经过格式化的名称,如: src/config/db.properties 设置 System.table.format = `[table]`,则返回  `tableName`。
	 * @return 格式化的表名称。
	 */
	public String getFormatName() {
		return getFormat().replaceFirst("\\[table\\]", name);
	}
	
	public String getFormatPrimaryKey(){
		return formatColumn(getPrimaryKey());
	}
	
	public String formatColumn(String column){
		return getColumnFormat().replaceFirst("\\[column\\]", column);
	}

	public static String formatColumn(Table table,String column){
		return table.getColumnFormat().replaceFirst("\\[column\\]", column);
	}
	
	public String getColumnFormat(){
		return columnFormat;
	}

	public String getFormat(){
		return format;
	}
	
	public String asNames(boolean skip,String...columns){
		StringBuffer names = new StringBuffer();
		List<String> atts;
		
		if(skip){
			atts = getColumns();
			atts.removeAll(Arrays.asList(columns));
		}else{
			if(columns.length == 0)
				atts = getColumns();
			else
				atts = Arrays.asList(columns);
		}
		
		int i = 0;
		for (Iterator<String> cs = atts.iterator(); cs.hasNext();) {
			String c = cs.next();
			names.append(asName(c));
			if (i < atts.size() - 1)
				names.append(",");
			
			i++;
		}
		return names.toString();
	}
	
	public String asNames(){
		return asNames(false,getColumns().toArray(new String[]{}));
	}
	
	public String asName(String column){
		return Utils.format("{0}.{1} AS {2}_{3}", getFormatName(), formatColumn(column),getName(),column);
	}

	
	/**
	 * 表示该表是否支持获取自增长的主键，可以设置为 src/config/db.properties [ModelName|System].primaryKey.call = true|false
	 * @return true为可以获取，false反之。
	 */
	public boolean isCall() {
		return call;
	}

	public Class<? extends AttributeMap> getPKType() {
		return pkType;
	}
	
	public DataSource getDataSource(){
		return dataSource;
	}
	
}
